import java.util.ArrayList;

/** A class representing a path in a graph that can be traced, etc.
    @param NI The information embedded within the nodes in which this path resides.
    @param LI The information embedded within the links in which this path resides.
    @author Ian Helmke, Dan King
*/
public class PathRoute<NI, LI> {
  /** Represents all the nodes on this path, in order. */
  private ArrayList<INode<NI, LI>> path;

  /** The constructor.
      @param path An ordered list of nodes which represents this path.
  */
  public PathRoute(ArrayList<INode<NI, LI>> path) {
    this.path = path;
  }


  public PathRoute(Iterable<INode<NI, LI>> path) {
    this.path = new ArrayList<INode<NI, LI>>();
    for (INode<NI, LI> node : path) {
      this.path.add(node);
    }
  }


  /** Determines if this path is valid. A path is valid if each node in
      the path is directly linked to the next node in the path.
      @return True if the path is valid, and False if it is not.
  */
  public boolean isPathValid() {
    for(int i = 0; i < path.size() - 1; i++) {
      INode<NI, LI> currentNode = path.get(i);
      INode<NI, LI> nextNode = path.get(i + 1);
      if (!this.routeBetween(currentNode, nextNode)) return false;
    }
    return true;
  }

  /** Determines if there is a route directly between the two given
      nodes.
      @param node1 The origin node.
      @param node2 The destination node.
      @return True if there is a direct route, and False otherwise.
  */
  private boolean routeBetween(INode<NI, LI> node1, INode<NI, LI> node2) {
    for(ILink<LI, NI> link : node1.getLinks())
      if (link.getDestination().equals(node2)) return true;
    return false;
  }

  /** Iterates through a path, calling methods on the associated
      TraceStrategy with every item hit.
      @param tracer The TraceStrategy whose methods will be called
                    as the path is traversed.
  */
  public <T> T tracePath(TraceStrategy<NI, LI, T> tracer) {
    if (!this.isPathValid()) return null;

    tracer.initTracer();

    //for(INode<NI, LI> node : path) {
    for(int i = 0; i < path.size() - 1; i++) {
      INode<NI, LI> currentNode = path.get(i);

      tracer.handleNode(currentNode);

      INode<NI, LI> nextNode = path.get(i + 1);

      for (ILink<LI, NI> link : currentNode.getLinks()) {
        if (link.getDestination() == nextNode) {
          tracer.handleLink(link);
          break;
        }

      }

    }
    return tracer.returnProduct();
  }

}
